package com.yonyou.ucf.mdd.ext.dubbo;

import com.yonyou.cloud.bean.GroupInfo;
import com.yonyou.cloud.bean.RemoteCallInfo;
import com.yonyou.cloud.common.IConfigKey;
import com.yonyou.cloud.middleware.MiddlewareRuntimeEnvironment;
import com.yonyou.cloud.mw.MwLocator;
import com.yonyou.cloud.mwclient.MwClientStartUp;
import com.yonyou.cloud.reqservice.IRemoteCallInfoManagerService;
import com.yonyou.ucf.mdd.common.exceptions.message.MddRuntimeMsgException;
import com.yonyou.ucf.mdd.common.exceptions.message.MsgExceptionCode;
import com.yonyou.ucf.mdd.ext.core.AppContext;
import com.yonyou.ucf.mdd.ext.middleware.IrisReference;
import com.yonyou.ucf.mdd.ext.util.localcache.AbstractSystemCacheUtil;
import com.yonyou.ucf.mdd.ext.util.localcache.RpcReferenceCacheUtil;
import com.yonyou.ucf.mdd.isv.service.ISVServiceFactory;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Collection;
import java.util.Optional;

public class DubboReference<T> {
    private static final Logger logger = LoggerFactory.getLogger(DubboReference.class);

    private AbstractSystemCacheUtil cache = RpcReferenceCacheUtil.getInstance();

    private static String DUBBO_TYPE = "dubbo";
    private static String IRIS_TYPE = "iris";

    private static String rpcType;

    static {
        try {
            Class.forName("com.yonyou.cloud.mw.MwLocator", false, DubboReference.class.getClassLoader());
            rpcType = System.getProperty("uretailRpcType");
        } catch (ClassNotFoundException e) {
            rpcType = DUBBO_TYPE;
        }
    }

    private static volatile DubboReference instance;

    protected DubboReference() {}

    public static DubboReference getInstance() {
        if (instance == null) {
            synchronized (DubboReference.class) {
                if (instance == null) {
                    instance = new DubboReference();
                }
            }
        }
        return instance;
    }

    /**
     * 调用远程服务
     *
     * @param
     * @param
     * @param group
     * @param version
     * @return
     * @throws IOException
     */
    public T getReference(Class<T> clazz, String group, String version) {
        return getReference(clazz, group, version, null);
    }

    public T getReference(Class<T> clazz, String group, String version, Integer timeout) {
        ISVServiceFactory isvBeanService = AppContext.getBean(ISVServiceFactory.class);
        T service = isvBeanService.getService(clazz, group, version, timeout);
        if (service != null) {
            return service;
        }
        T result;
        logger.debug("rpc type配置项为={}, group={}", rpcType, group);
        result = getIrisiBillQueryService(clazz, group);
        if (null != result) {
            logger.debug("获取iris ref成功");
            return result;
        } else {
            logger.debug("获取iris ref失败! group:{}", group);
            throw new MddRuntimeMsgException(MsgExceptionCode.RPC_ITF_PROXY_ISNULL);
        }
    }

    private T getIrisiBillQueryService(Class clazz, String group) {
        T irisRef = getIrisRef(group, clazz, false);
        if (irisRef != null) {
            return irisRef;
        }
        return null;
    }

    private T getIrisRef(String group, Class<?> interfaceClass, boolean check) {
        // iris 未启动
        if (!MwClientStartUp.getstatus()) {
            logger.warn("iris rpc 未启动");
            return null;
        }
        // 如果为本域查询 则获取本地的实现类
        String parent =
                GroupInfo.getGroup(group, MiddlewareRuntimeEnvironment.get(IConfigKey.Keys.PROVIDER_ID));
        if (group.equals(MiddlewareRuntimeEnvironment.get(IConfigKey.Keys.APP_CODE))
                || MiddlewareRuntimeEnvironment.get(IConfigKey.Keys.APP_CODE).equals(parent)) {
            Collection<RemoteCallInfo> rcis =
                    MwLocator.lookup(IRemoteCallInfoManagerService.class).getAllRemoteCallInfo();
            Optional<RemoteCallInfo> remoteCallInfo =
                    rcis.stream()
                            .filter(rci -> interfaceClass.getName().equals(rci.getClassName()))
                            .findFirst();
            if (remoteCallInfo.isPresent()) {
                RemoteCallInfo rci = remoteCallInfo.get();
                String beanid = rci.getBeanId();
                if (StringUtils.isNotBlank(beanid)) { // 多实现的时候必须要注册实现的beanid
                    return (T) AppContext.getBean(beanid, interfaceClass);
                } else { // 单实现的时候beanid可能为空
                    try {
                        return (T) AppContext.getBean(interfaceClass);
                    } catch (Exception e) {
                        logger.error("根据RPC 接口Class获取实现类失败，e: {}", e);
                    }
                }
            } else {
                logger.error("remoteCallInfo is empty ,默认根据class获取");
                try {
                    return (T) AppContext.getBean(interfaceClass);
                } catch (Exception e) {
                    logger.error("remoteCallInfo is empty ,默认根据class获取实现类失败，e: {}", e);
                }
            }
        }
        try {
            String publicCacheKeys = AppContext.getEnvConfig("publicCacheKeys");
            if (StringUtils.isNotEmpty(publicCacheKeys)) {
                //AppContext.bulidResCacheMap(true, AppContext.getCurrentUserNoCallBack());
            }
        } catch (Exception e) {
            logger.error("bulidResCacheMap", e);
        }
        logger.debug("iris 延用dubbo调用设置rpcToken的逻辑");

        IrisReference<T> result;
        String irisCacheKey = String.format("%s_%s_%s", IRIS_TYPE, interfaceClass.getName(), group);

        if (cache.containsKey(irisCacheKey)) {
            result = cache.get(irisCacheKey);
        } else {
            result = new IrisReference<>(interfaceClass, group);
            cache.put(irisCacheKey, result);
        }
        return check ? result.getRef() : result.getRefNoCheck();
    }

    public static String getProperty(String property) {
        String value = AppContext.getEnvConfig(property);
        return value;
    }
}
